# -*- coding:utf-8 -*-
import copy
import hashlib
import json
import time
from json.decoder import JSONDecodeError

from bigchaindb.common.transaction import Transaction
from bson import ObjectId

from bigchaindb import Bigchain, backend
from bigchaindb.common import crypto
from django.http import HttpResponse
from rest_condition import Or
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response

from blockchainrestful.bill import Bill
from blockchainrestful.custom import IsAdmin
from blockchainrestful.custom import IsManager
from blockchainrestful.custom import IsTest
from blockchainrestful.custom import IsUser
from bson import json_util
from blockchainrestful.wallet import Wallet

import logging
import pymongo

# logger = logging.getLogger('blockchainrestful.views')
# conn = pymongo.MongoClient(host='127.0.0.1', port=27017)
# db = conn['bigchain']
#
# b = Bigchain()
# wallet = Wallet()
# bill = Bill()


# @api_view(['GET'])
# def get_block_by_height(request, height, format=None):
#     """
#     通过区块高度返回区块
#     输入：区块高度
#     输出：区块信息
#     """
#     cursor = db['bigchain'].find_one({'block_number': int(height)})
#     # cursor = r.table('bigchain').filter({'block_number': int(height)}).run(conn)
#     if cursor.threshold != 0:
#         block = cursor.next()
#         cursor.close()
#         return Response(block)
#     else:
#         cursor.close()
#         return Response(status=status.HTTP_204_NO_CONTENT)


# @api_view(['GET'])
# def get_block_by_transaction_id(request, transaction_id, format=None):
#     """
#     通过交易id查询区块
#     输入：交易id
#     输出：包含该条交易的区块信息
#     """
#     cursor = db['bigchain'].find_one(lambda bigblock: bigblock['block']['transactions']['id']
#                                      .contains(transaction_id))
#     # cursor = r.table('bigchain').filter(lambda bigblock: bigblock['block']['transactions']['id']
#     #                                     .contains(transaction_id)).run(conn)
#     if cursor.threshold != 0:
#         block = cursor.next()
#         cursor.close()
#         return Response(block)
#     else:
#         cursor.close()
#         return Response(status=status.HTTP_204_NO_CONTENT)


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_transaction_by_id(request, id, format=None):
    """
    通过交易id查询交易
    输入：交易id
    输出：交易信息
    """
    b = Bigchain()
    tx = b.get_transaction(id)
    if tx is not None:
        return Response(tx)
    else:
        return Response(status=status.HTTP_204_NO_CONTENT)


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_balance(request, key, format=None):
    print('----get_balance--start----', time.time())

    wallet = Wallet()
    total = wallet.get_total_money(key)
    print('----get_total_money--end----', time.time())
    return Response({'pub_key': key, 'balance': total})


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_transdetail(request, key, format=None):
    print('----get_transdetail--start----', time.time())
    start = request.GET.get('start')
    end = request.GET.get('end')
    if start == None or end == None:
        return Response({'error': '开始结束时间不能为空'})
    return Response({'pub_key': key, 'transdetail': get_translist(key, start, end)})


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_depositdetail(request, key, format=None):
    print('----get_depositdetail--start----', time.time())

    b = Bigchain()
    wallet = Wallet()
    payer = request.GET.get('from')

    payer = payer.replace('"','')
    startTime = request.GET.get('startTime') + ' 00:00:00'
    endTime = request.GET.get('endTime') + ' 23:59:59'
    if startTime == None:
        return Response({'error': '开始时间不能为空'})
    if endTime == None:
        return Response({'error': '结束时间不能为空'})
    if payer == None:
        return Response({'error': '发薪公司不能为空'})
    startStamp = int(time.mktime(time.strptime(startTime, "%Y-%m-%d %H:%M:%S")))
    endStamp = int(time.mktime(time.strptime(endTime, "%Y-%m-%d %H:%M:%S")))
    list = [
        {'$match': {'$and': [{'block.transactions.metadata.banktime': {'$gt': startStamp}},
                             {'block.transactions.metadata.banktime': {'$lt': endStamp}},
                             {'block.transactions.metadata.from.name': payer},
                             {'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'block.transactions.inputs.owners_before': key}]}},
        {'$unwind': '$block.transactions'},
        {'$match': {'$and': [{'block.transactions.metadata.banktime': {'$gt': startStamp}},
                             {'block.transactions.metadata.banktime': {'$lt': endStamp}},
                             {'block.transactions.metadata.from.name': payer},
                             {'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'block.transactions.inputs.owners_before': key}]}},
        {"$sort": {'block.transactions.metadata.group': -1}}
    ]
    txs = b.getTxByList(list)
    print('----b.get_depositdetail--end----', time.time())
    lis = []
    for tx in txs:
        dic = {}
        dic['timestamp'] = candr(tx['metadata'], 'banktime')
        dic['amount'] = tx['outputs'][0]['amount']
        dic['receive_pubk'] = tx['outputs'][0]['public_keys'][0]
        dic['time'] = tx['metadata']['time']
        dic['clientID'] = candr(tx['metadata'], 'clientID')
        lis.append(dic)
    return Response({'pub_key': key, 'depositdetail': lis})


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_payeeinfo(request, key, format=None):
    print('----get_payeeinfo--start----', time.time())
    limit = request.GET.get('limit')
    print('limit', limit)
    if limit == None:
        return Response({'token': key, 'payeeinfo': get_payeelist(key)})
    return Response({'token': key, 'payeeinfo': get_payeelist(key, int(limit))})


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager, IsUser),))
def get_version(request, format=None):
    from restfulwebservice.settings import VERSION
    return Response({'version': VERSION})


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager, IsUser),))
def get_key_pair(request, format=None):
    """
    获取秘钥
    输入：无
    输出：公钥和私钥
    """
    private_key, public_key = crypto.generate_key_pair()
    return Response({'priv_key': private_key, 'pub_key': public_key})


@api_view(['POST'])
@permission_classes((Or(IsAdmin, IsManager),))
def sign_fulfillment(request, key, format=None):
    """
    """
    print('----sign_fulfillment--start----', time.time())

    b = Bigchain()
    wallet = Wallet()
    data = request.data
    print('---sign_fulfillment---dic-------', data)
    dics = data['transactions']
    txids = []
    for dic in dics:
        txid = dic['txids']
        fulfillment = dic['fulfillment']
        tx = b.get_unsigned_transaction(txid=txid)
        if tx is None:
            return Response({'error': '请求提交重复'})
        subfulfillments = []
        for subful in tx['inputs'][0]['fulfillment']['subfulfillments']:
            if subful['weight'] == 2:
                subful['signature'] = fulfillment
                subfulfillments.append(subful)
            else:
                pass
        tx['inputs'][0]['fulfillment']['subfulfillments'] = subfulfillments
        tx = Transaction.from_dict(tx=tx)
        txids.append(txid)
        b.write_transaction(tx)

    ret = wallet.wait_for_tx_result(txids, 30)
    if not ret["ret"]:
        print(ret["err"])
        wallet.rollback(ret['succ_txids'])
        print('sign_fulfillment : error')
        return Response({'error': ret["err"]})
    else:
        for txid in txids:
            b.delete_unsinged_transaction(txid)
    print('sign_fulfillment : successful')
    return Response({'ok': 'successful'})


@api_view(['POST'])
@permission_classes((Or(IsAdmin, IsManager),))
def create_transaction(request, key, format=None):
    """
    区块创建Create交易
    输入：前一个交易id(previous_process_tx_id)
         公钥(public_key)
         人员(who: {original: whoItem, goto: whoItem})，
         whoItem: user_id, user_type, user_name, company_name, company_id, u_company_id
         地点(where: {original: whereItem, goto: whereItem})
         whereItem: nation, region, place, region_id
         时间(when: make_date, send_date, receive_date, expire_date)
         物品(thing: thing_type_id, thing_type_name, thing_id, thing_name, origin_place, thing_order_quantity, thing_order_batch, price)
    输出：交易id
    """
    print('----create_transaction--start----', time.time())

    wallet = Wallet()
    start = time.time()
    data = request.data
    print('create_transaction--------->', data)
    print('key--------->', key)
    amount = data['amount']

    meta = {}
    meta['from'] = candr(data, 'from')
    meta['comment'] = candr(data, 'comment')
    meta['time'] = candr(data, 'time')
    meta['banktime'] = int(time.mktime(time.strptime(meta['time'], "%Y-%m-%d %H:%M:%S")))
    meta['clientID'] = candr(data, 'clientID')
    meta['type'] = wallet.TRANSAC_TYPE['tran']

    if key == wallet.BANK_PUB_KEY_NEW or key == wallet.BANK_PUB_KEY:
        print('deposit_money start')
        ret = wallet.deposit_money(account=data['receive_pubk'], amount=amount, metadata=meta)
        if ret['ret']:
            print('deposit_money success')
            return Response({'operation': data['operation']})
        else:
            print('deposit_money error')
            return Response({'error': ret["err"]})

    keyfree = bool(data['keyfree'])

    meta['to'] = candr(data, 'to')
    print('transfer_money start')
    if keyfree:
        if 'receive_pubk' in data:  # to phone
            ret = wallet.transfer_money(account_from=key, account_to=data['receive_pubk'], amount=data['amount'],
                                        metadata=meta, keyfree=True)
        else:  # to bank
            ret = wallet.transfer_money(account_from=key, amount=data['amount'],
                                        account_to=wallet.BLACKHOLE_PUB_KEY_NEW,
                                        metadata=meta, keyfree=True)

        if not ret["ret"]:
            print("transfer_money", "error")
            return Response({'error': ret["err"]})
        print("transfer_money", "success")
        return Response({'operation': data['operation'], 'clientID': candr(data, 'clientID')})
    else:
        return create_transaction_keyferrfalse(data=data, key=key)


def create_transaction_keyferrfalse(data, key):
    b = Bigchain()
    wallet = Wallet()
    data = data
    meta = {}
    meta['from'] = candr(data, 'from')
    meta['to'] = candr(data, 'to')
    meta['comment'] = candr(data, 'comment')
    meta['time'] = candr(data, 'time')
    meta['banktime'] = int(time.mktime(time.strptime(meta['time'], "%Y-%m-%d %H:%M:%S")))
    meta['clientID'] = candr(data, 'clientID')
    meta['type'] = wallet.TRANSAC_TYPE['tran']

    if 'receive_pubk' in data:  # to phone
        txids = wallet.transfer_money(account_from=key, account_to=data['receive_pubk'], amount=data['amount'],
                                      metadata=meta, keyfree=False)
    else:  # to bank
        txids = wallet.transfer_money(account_from=key, amount=data['amount'], account_to=wallet.BLACKHOLE_PUB_KEY_NEW,
                                      metadata=meta, keyfree=False)

    if 'ret' in txids:
        if not txids["ret"]:
            pass  # TODO meybe need rollback
        print("transfer_money", "error")
        return Response({'error': txids["err"]})
    lis = []
    for txid in txids:
        count = 0
        while True:
            tx = b.get_unsigned_transaction(txid=txid)
            if tx is None:
                pass
            else:
                tx = Transaction._remove_signatures(tx)
                tx_serialized = Transaction._to_str(tx)
                dic = {'txids': txid, 'data': md5(tx_serialized.encode()).decode()}
                lis.append(dic)
                break
            interval = 0.2
            time.sleep(interval)
            count = count + interval
            if count >= 25:
                print('---------timeout=5s----------')
                break
    print('transfer_money lis', lis)
    return Response({'operation': data['operation'], 'transactions': lis, 'clientID': candr(data, 'clientID')})


def md5(src):
    m2 = hashlib.md5()
    m2.update(src)
    return m2.hexdigest().encode()


# Check that tag is in data and return data[tag]
def candr(data, tag):
    if tag in data:
        return data[tag]
    else:
        return ''


# bill
def error(sts, msg):
    '''
    make error message to client
    Para:
      sts - int, status of HTTP response
      mag - string of message
    Return:
      Response
    '''
    return Response({'error': msg}, status=sts)


def field_filter(source, fields):
    '''
    filter fields
    Para:
      source - dict
      fields - list of string
    Retrun:
      list
    '''
    if len(fields) == 0:
        ans = source
    else:
        ans = {}
        for field in fields:
            try:
                ans[field] = source[field]
            except KeyError:
                pass
    return ans


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def transaction(request, id, format=None):
    '''
    URL:
      transaction/[id]
    Use for:
      get one transaction data by id
    Para:
      field - field to filter json dict
    Return:
      a json dict
    '''
    # get paras

    b = Bigchain()
    fields = request.GET.getlist('field')
    # get transaction
    data = b.get_transaction(id)
    if data == None:
        return error(404, 'can not find this transaction')
    else:
        return Response(field_filter(data, fields))


def get_payeelist(pub_key, limit=10):
    # response = backend.query.get_owners_before(b.connection, pub_key)
    # txs, indexs = b.get_tx_inputs(pub_key)

    b = Bigchain()
    wallet = Wallet()
    list = [
        {'$match': {'$and': [{'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'block.transactions.inputs.owners_before': pub_key}]}},
        {'$unwind': '$block.transactions'},
        {'$match': {'$and': [{'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'block.transactions.inputs.owners_before': pub_key}]}},
        {"$sort": {'block.transactions.metadata.group': -1}}
    ]
    response = backend.query.getTxByList(b.connection, list)
    lis = []
    # print('limit---->', limit)
    for tx in response:
        if len(lis) >= limit:
            break
        # tx = txs[i]
        # print('tx------->', tx)
        dic = {}
        if 'to' in tx['metadata']:
            dic['name'] = tx['metadata']['to']['name']
            if 'bank' in tx['metadata']['to']:
                dic['bank'] = tx['metadata']['to']['bank']

            if 'phone' in tx['metadata']['to']:
                dic['phone'] = tx['metadata']['to']['phone']
                if 'from' in tx['metadata']:
                    if 'phone' in tx['metadata']['from']:
                        if tx['metadata']['to']['name'] == dic['name'] and dic['phone'] == tx['metadata']['from'][
                            'phone']:
                            continue

            if 'account' in tx['metadata']['to']:
                dic['account'] = tx['metadata']['to']['account']

            dic['timestamp'] = candr(tx['metadata'], 'banktime')
            dic['group'] = tx['metadata']['group']
            if len(lis) == 0:
                lis.append(dic)
            else:
                for j in range(len(lis)):
                    if lis[j]['group'] == tx['metadata']['group']:
                        break
                    if lis[j]['name'] == tx['metadata']['to']['name']:
                        if 'phone' in lis[j] and 'phone' in tx['metadata']['to']:
                            if lis[j]['phone'] == tx['metadata']['to']['phone']:
                                break

                        if 'account' in lis[j] and 'account' in tx['metadata']['to']:
                            if lis[j]['account'] == tx['metadata']['to']['account']:
                                break
                else:
                    lis.append(dic)
    # print('----get_payeelist--lis------->', lis)
    print('----get_payeelist--lis--end----->', time.time())
    return lis


def get_translist(pub_key, start, end):
    b = Bigchain()
    wallet = Wallet()
    mongo_lis = [
        {'$match': {'$and': [{'$or': [{'block.transactions.inputs.owners_before': pub_key},
                                      {'block.transactions.outputs.public_keys': pub_key}]},
                             {'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'block.transactions.metadata.banktime': {'$gt': int(start)}},
                             {'block.transactions.metadata.banktime': {'$lt': int(end)}}]}},
        {'$unwind': '$block.transactions'},
        {'$match': {'$and': [{'$or': [{'block.transactions.inputs.owners_before': pub_key},
                                      {'block.transactions.outputs.public_keys': pub_key}]},
                             {'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'block.transactions.metadata.banktime': {'$gt': int(start)}},
                             {'block.transactions.metadata.banktime': {'$lt': int(end)}}]}}
    ]
    lis = []
    # curser = b.get_transactions(pub_key, days)
    curser = b.getTxByList(mongo_lis)
    for block in curser:
        # block.pop('_id')
        # print('block--->', block)
        # for j in range(len(block['block']['transactions'])):
        if block['metadata']['asset'] == wallet.ASSET_TYPE['money']:
            dic = {}
            dic['timestamp'] = candr(block['metadata'], 'banktime')
            dic['group'] = block['metadata']['group']
            dic['time'] = candr(block['metadata'], 'time')
            dic['comment'] = candr(block['metadata'], 'comment')
            dic['clientID'] = candr(block['metadata'], 'clientID')

            if 'to' in block['metadata']:
                if block['inputs'][0]['owners_before'][0] == pub_key:
                    dic['type'] = '转出'
                    dic['payee'] = block['metadata']['to']['name']

                    if 'bank' in block['metadata']['to']:
                        dic['bank'] = block['metadata']['to']['bank']
                    if 'phone' in block['metadata']['to']:
                        dic['phone'] = block['metadata']['to']['phone']

                    if 'account' in block['metadata']['to']:
                        dic['account'] = block['metadata']['to']['account']

                    for i in range(len(block['outputs'])):
                        if block['outputs'][i]['public_keys'][0] == pub_key:
                            pass
                        else:
                            if len(lis) == 0:
                                dic['amount'] = -block['outputs'][i]['amount']
                                lis.insert(0, dic)
                            else:
                                # print('lis-bef->', lis[0]['timestamp'])
                                # print('blo-bef->', block['metadata']['group'])
                                # print('amount-bef->', lis[0]['amount'])

                                if lis[0]['group'] == block['metadata'][
                                    'group']:
                                    lis[0]['amount'] = lis[0]['amount'] - \
                                                       block['outputs'][i][
                                                           'amount']
                                else:
                                    dic['amount'] = -block['outputs'][i]['amount']
                                    lis.insert(0, dic)

                                    # print('amount-bef->', lis[0]['amount'])
                else:
                    dic['type'] = '转入'
                    dic['payer'] = block['metadata']['from']['name']

                    if 'bank' in block['metadata']['from']:
                        dic['bank'] = block['metadata']['from']['bank']
                    if 'phone' in block['metadata']['from']:
                        dic['phone'] = block['metadata']['from']['phone']

                    if 'account' in block['metadata']['from']:
                        dic['account'] = block['metadata']['from']['account']
                    for i in range(len(block['outputs'])):
                        if block['outputs'][i]['public_keys'][0] == pub_key:
                            if len(lis) == 0:
                                dic['amount'] = block['outputs'][i]['amount']
                                lis.insert(0, dic)
                            else:
                                # print('lis-pub->', lis[0]['timestamp'])
                                # print('blo-pub->', block['metadata']['group'])
                                # print('amount-pub->', lis[0]['amount'])

                                if lis[0]['group'] == block['metadata'][
                                    'group']:
                                    lis[0]['amount'] = lis[0]['amount'] + \
                                                       block['outputs'][i][
                                                           'amount']
                                else:
                                    dic['amount'] = block['outputs'][i]['amount']
                                    lis.insert(0, dic)

                                    # print('amount-pub->', lis[0]['amount'])
                        else:
                            pass
            elif 'from' in block['metadata']:
                dic['type'] = '转入'
                dic['payer'] = block['metadata']['from']['name']
                dic['bank'] = candr(block['metadata']['from'], 'bank')
                dic['account'] = candr(block['metadata']['from'], 'account')

                for i in range(len(block['outputs'])):
                    if block['outputs'][i]['public_keys'][0] == pub_key:
                        if len(lis) == 0:
                            dic['amount'] = block['outputs'][i]['amount']
                            lis.insert(0, dic)
                        else:
                            if lis[0]['group'] == block['metadata'][
                                'group']:
                                lis[0]['amount'] = lis[0]['amount'] + \
                                                   block['outputs'][i][
                                                       'amount']
                            else:
                                dic['amount'] = block['outputs'][i]['amount']
                                lis.insert(0, dic)
                    else:
                        pass

    return lis


@api_view(['POST'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_bill_detail(request, key, format=None):
    """
    """
    print('----get_bill_detail--start----', time.time())

    bill = Bill()
    data = request.data
    dics = data['blockchaininfo']
    txid = dics['txid']
    idx = dics['idx']
    pub_key = key

    dic = {}
    tx = bill.b.get_transaction(txid)
    ess = bill.get_endorse(txid, key)
    bill.endorse = []
    endorse = []
    for i in range(len(ess)):
        if i == 0:
            continue
        es = ess[i]
        d = {}
        d['endorsee'] = es.metadata['to']['name']
        d['endorser'] = es.metadata['from']['name']
        d['time'] = es.metadata['time']
        d['clientID'] = es.metadata['clientID']
        d['comment'] = es.metadata['comment']
        endorse.append(d)
    dic['endorse'] = endorse
    print('-------endorse------', endorse)
    dic['pub_key'] = pub_key
    dic_bill = ess[0].metadata['bill']
    dic_bill['amount'] = tx.outputs[idx].amount
    dic_bill['time'] = ess[0].metadata['time']
    dic_bill['clientID'] = ess[0].metadata['clientID']
    dic_bill['comment'] = ess[0].metadata['comment']
    dic['bill'] = dic_bill

    return Response(dic)


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_bill_list(request, key, format=None):
    """
    """
    print('----get_bill_list----', time.time())

    bill = Bill()

    dic = {}
    bill_list = bill.get_bill_list(key)
    # print('----bill_list----',len(bill_list))
    billlist = []
    for bill_info in bill_list:
        pub_key = key
        dic_bill = {}
        amount = bill_info['amount']
        dic_bill['amount'] = amount

        meta_create = bill.b.get_transaction(bill_info['asset_id']).metadata
        if 'bill' in meta_create:
            dic_bill['expdate'] = meta_create['bill']['expdate']
            dic_bill['protocol'] = meta_create['bill']['protocol']
            dic_bill['acceptor'] = meta_create['bill']['acceptor']
            dic_bill['guarantee'] = meta_create['bill']['guarantee']
            dic_bill['accepBillNo'] = meta_create['bill']['accepBillNo']
        else:
            return Response({'error': 'the create module is wrong,there are not {drawer,guarantee,expdate,protocol}'})
        dic_bill['timestamp'] = meta_create['banktime']
        tx = bill.b.get_transaction(bill_info['translink'].txid)
        payhistory = []
        while tx.inputs[0].to_dict()['owners_before'][0] == pub_key or (
                        candr(candr(tx.metadata, 'from'), 'name') == candr(candr(tx.metadata, 'to'), 'name') and
                        candr(tx.metadata, 'comment') == "余额结转"):
            if tx.inputs[0].to_dict()['owners_before'][0] == pub_key:  # 自己转给自己的情况，转给别人剩余的给自己
                dic_payhistory = {}
                meta_pay = tx.metadata
                dic_payhistory['payee'] = meta_pay['to']['name']
                for output in tx.outputs:
                    if output.public_keys[0] != pub_key:
                        dic_payhistory['amount'] = output.amount
                dic_payhistory['time'] = meta_pay['time']
                dic_payhistory['clientID'] = candr(meta_pay, 'clientID')
                dic_payhistory['comment'] = candr(meta_pay, 'comment')
                payhistory.insert(0, dic_payhistory)
            else:  # 余额结转
                pub_key = tx.inputs[0].to_dict()['owners_before'][0]
            tx = bill.b.get_transaction(tx.inputs[0].to_dict()['fulfills']['txid'])
        else:
            for output in tx.outputs:
                if output.public_keys[0] == pub_key:
                    print('===tx.id====', tx.id)
                    print('===output.amount====', output.amount)
                    dic_bill['totalAmount'] = output.amount
        meta_tran = tx.metadata
        dic_bill['payhistory'] = payhistory

        dic_bill['comment'] = candr(meta_tran, 'comment')

        dic_bill['payer'] = meta_tran['from']['name']
        dic_bill['time'] = meta_create['time']
        dic_bill['clientID'] = candr(meta_create, 'clientID')
        blockchaininfo = {}
        blockchaininfo['txid'] = bill_info['translink'].txid
        blockchaininfo['idx'] = bill_info['translink'].output
        dic_bill['blockchaininfo'] = blockchaininfo
        billlist.append(dic_bill)
    dic['billlist'] = billlist
    dic['pub_key'] = key
    return Response(dic)


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_bill_billtreeinfo(request, key, format=None):
    """
    """
    print('----get_bill_billtreeinfo--start----', time.time())

    b = Bigchain()
    bill = Bill()
    accepBillNo = request.GET.get('accepBillNo')

    dic = {}
    blocks = b.getTxByKeyValue('block.transactions.metadata.bill.accepBillNo', accepBillNo)
    # blocks, idxs = bill.b.get_tx_inputs(key)
    print('----blocks----', len(blocks))
    billtreeinfo = []
    for block in blocks:
        if block['metadata']['asset'] == bill.ASSET_TYPE['bill']:
            if block['operation'] == 'CREATE':
                meta_create = block['metadata']
                if 'bill' in meta_create:
                    if accepBillNo == meta_create['bill']['accepBillNo']:
                        assetid = block['id']
                        mongl = [
                            {'$match': {'$or': [{'block.transactions.id': assetid},
                                                {'block.transactions.asset.id': assetid}]}},
                            {'$unwind': '$block.transactions'},
                            {'$match': {'$or': [{'block.transactions.id': assetid},
                                                {'block.transactions.asset.id': assetid}]}},
                            {"$sort": {'block.transactions.metadata.group': -1}}
                        ]
                        # trans = b.get_transactions_byassetid(assetid)
                        trans = b.getTxByList(mongl)
                        for tran in trans:
                            for i in range(len(tran['outputs'])):
                                dic_bill = {}
                                dic_bill['id'] = '%s%s%d' % (tran['id'], '_', i)
                                dic_bill['pubkey'] = tran['outputs'][i]['public_keys'][0]
                                dic_bill['amount'] = tran['outputs'][i]['amount']

                                dic_bill['time'] = tran['metadata']['time']
                                if tran['inputs'][0]['fulfills'] == None:
                                    dic_bill['super_id'] = ""
                                else:
                                    dic_bill['super_id'] = '%s%s%d' % (
                                        tran['inputs'][0]['fulfills']['txid'], '_',
                                        tran['inputs'][0]['fulfills']['output'])
                                billtreeinfo.append(dic_bill)
                        break
                else:
                    return Response(
                        {'error': 'the create module is wrong,there are not {drawer,guarantee,expdate,protocol}'})
    dic['billtreeinfo'] = billtreeinfo
    return Response(dic)


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_bill_billtrans(request, format=None):
    """
    """
    print('----get_bill_billtrans--start----', time.time())

    b = Bigchain()
    wallet = Wallet()
    mubiaotxid = request.GET.get('txid')

    mongl = [
        {'$match': {'block.transactions.inputs.fulfills.txid': mubiaotxid}},
        {'$unwind': '$block.transactions'},
        {'$match': {'block.transactions.inputs.fulfills.txid': mubiaotxid}},
        {"$sort": {'block.transactions.inputs.fulfills.output': -1}}
    ]

    trans = b.getTxByList(mongl)
    requlist = []
    for block in trans:
        dic = {}
        dic['timestamp'] = block['metadata']['banktime']
        dic['group'] = block['metadata']['group']
        dic['metadata'] = block['metadata']
        dic['time'] = candr(block['metadata'], 'time')

        dic['RESUME'] = candr(block['metadata'], 'comment')
        dic['clientID'] = candr(block['metadata'], 'clientID')
        dic['blockID'] = block['id']

        iscontinue = False
        for i in range(len(requlist)):
            if dic['blockID'] == requlist[i]['blockID']:
                iscontinue = True
                break

        if iscontinue:
            continue

        if 'TRANSFER' == block['operation']:
            dic['inputkey'] = block['inputs'][0]['owners_before'][0]
            dic['type'] = 'TRANSFER out'
            dic['idx'] = block['inputs'][0]['fulfills']['output']
            for i in range(len(block['outputs'])):
                if block['outputs'][i]['public_keys'][0] == dic['inputkey']:
                    pass
                else:
                    if block['outputs'][i]['public_keys'][0] == wallet.BLACKHOLE_PUB_KEY or \
                                    block['outputs'][i]['public_keys'][
                                        0] == wallet.BLACKHOLE_PUB_KEY_NEW:
                        dic['OPPACCNO'] = candr(candr(block['metadata'], 'to'), 'account')
                    else:
                        dic['outputkey'] = block['outputs'][i]['public_keys'][0]
                    dic['TRANAMT'] = block['outputs'][i]['amount']
                    requlist.insert(0, dic)

        elif 'CREATE' == block['operation']:
            # dic['subAccNo1'] = block['inputs'][0]['owners_before'][0]#yinhang
            dic['outputkey'] = block['outputs'][0]['public_keys'][0]  # ziji
            dic['TRANAMT'] = block['outputs'][0]['amount']
            dic['type'] = 'CREATE'
            requlist.insert(0, dic)
    return Response({'statement': requlist})



@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_bill_transdetail(request, key, format=None):
    """
    """
    print('----get_bill_transdetail--start----', time.time())

    bill = Bill()
    days = request.GET.get('days')
    if days == None:
        return Response({'pub_key': key, 'transdetail': bill.get_translist(key)})
    return Response({'pub_key': key, 'transdetail': bill.get_translist(key, int(days))})


@api_view(['POST'])
@permission_classes((Or(IsAdmin, IsManager),))
def create_bill_trans(request, key, format=None):
    """
    """
    print('----create_bill_trans--start----', time.time())

    bill = Bill()
    b = Bigchain()
    wallet = Wallet()
    data = request.data
    print('create_bill_trans--------->{},key:{}'.format(data, key))
    meta = {}
    meta['operation'] = data['operation']
    meta['from'] = data['from']
    meta['to'] = data['to']
    meta['comment'] = candr(data, 'comment')
    meta['clientID'] = data['clientID']
    meta['time'] = data['time']
    meta['banktime'] = int(time.mktime(time.strptime(meta['time'], "%Y-%m-%d %H:%M:%S")))

    if (key == bill.BANK_PUB_KEY_NEW or key == bill.BANK_PUB_KEY) and data['operation'] == 'create':
        if not 'bill' in data:
            return Response({'error': '票据信息不能为空'})
        meta['bill'] = data['bill']
        print('deposit_bill start metadata is :', meta)
        ret = bill.deposit_bill(account=data['receive_pubk'], amount=data['amount'], metadata=meta)
        if ret['ret']:
            print('--------deposit_bill--ok------->')
            return Response({'operation': data['operation'], "txid": ret["succ_txids"][0]})
        else:
            print('--------deposit_bill--error------->', ret["err"])
            return Response({'error': ret["err"]})

    txid = data['blockchaininfo']['txid']
    idx = data['blockchaininfo']['idx']

    tx = bill.b.get_transaction(txid=txid)
    if tx == None:
        return Response({'error': '这张票据不存在'})

    if tx.outputs[idx].amount < data['amount']:
        return Response({'error': '这张票据余额不足'})

    if b.get_spent(txid, idx):
        return Response({'error': '这张票据已经被花费'})

    if data['keyfree']:
        if 'receive_pubk' in data:
            ret = bill.transfer_bill(account_from=key, amount=data['amount'], account_to=data['receive_pubk'],
                                     txid=txid, idx=idx, metadata=meta, keyfree=True)
        else:
            ret = bill.transfer_bill(account_from=key, amount=data['amount'], account_to=wallet.BLACKHOLE_PUB_KEY_NEW,
                                     txid=txid, idx=idx, metadata=meta, keyfree=True)
        if not ret["ret"]:
            print('--------transfer_bill-keyfree=True-error------->', ret["err"])
            return Response({'error': ret["err"]})
        print('--------transfer_bill-keyfree=True-ok------->')
        return Response({'operation': data['operation'], "txid": ret["succ_txids"][0]})
    else:
        if 'receive_pubk' in data:
            txids = bill.transfer_bill(account_from=key, account_to=data['receive_pubk'], amount=data['amount'],
                                       txid=txid, idx=idx, metadata=meta, keyfree=False)
        else:  # duifu  xuyao tieka
            txids = bill.transfer_bill(account_from=key, amount=data['amount'], account_to=wallet.BLACKHOLE_PUB_KEY_NEW,
                                       txid=txid, idx=idx, metadata=meta, keyfree=False)
        if 'ret' in txids:
            # if not txids["ret"]:
            #     pass  # TODO meybe need rollback
            print('--------transfer_bill-keyfree=False-error------->', txids["err"])
            return Response({'error': txids["err"]})
        lis = []
        for txid in txids:
            count = 0
            while True:
                tx = b.get_unsigned_transaction(txid=txid)
                if tx is None:
                    pass
                else:
                    tx = Transaction._remove_signatures(tx)
                    tx_serialized = Transaction._to_str(tx)
                    dic = {'txids': txid, 'data': md5(tx_serialized.encode()).decode()}
                    lis.append(dic)
                    break
                interval = 0.2
                time.sleep(interval)
                count = count + interval
                if count >= 25:
                    print('---------timeout=5s----------')
                    break
        print('transfer_bill lis', lis)
        return Response({'operation': data['operation'], 'transactions': lis})


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_bill_depositlist(request, key, format=None):
    print('----get_bill_depositlist--start----', time.time())
    bill = Bill()
    b = Bigchain()
    payer = request.GET.get('from')
    # year = request.GET.get('year')
    # month = request.GET.get('month')
    if payer == None:
        return Response({'error': 'from or year or month is null'})
    txs = b.get_depositdetail(owner=key, payer=payer)
    lis = []

    for tx in txs:
        if not bill.ASSET_TYPE['bill'] == tx['metadata']['asset']:
            continue
        dic = {}
        dic['timestamp'] = tx['metadata']['banktime']
        dic['amount'] = tx['outputs'][0]['amount']
        dic['time'] = tx['metadata']['time']
        dic['clientID'] = tx['metadata']['clientID']
        dic['comment'] = tx['metadata']['comment']
        if 'bill' in tx['metadata']:
            dic['acceptor'] = tx['metadata']['bill']['acceptor']
            dic['accepBillNo'] = tx['metadata']['bill']['accepBillNo']
            dic['guarantee'] = tx['metadata']['bill']['guarantee']
            dic['expdate'] = tx['metadata']['bill']['expdate']
            dic['protocol'] = tx['metadata']['bill']['protocol']
            dic['payer'] = tx['metadata']['bill']['payer']
            dic['payee'] = tx['metadata']['bill']['payee']

        else:
            return Response({'error': 'the create module is wrong,there are not {drawer,guarantee,expdate,protocol}'})

        lis.append(dic)
    return Response({'pub_key': key, 'depositdetail': lis})



@api_view(['POST'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_transtatus(request, format=None):
    print('----get_bill_depositlist--start----', time.time())
    b = Bigchain()
    data = request.data
    clientID = data['clientID']
    tx_ids = data['txids']
    if clientID == None:
        return Response({'error': 'clientID is null'})
    list_mongo = [
        {'$match': {'block.transactions.metadata.clientID': clientID}},
        {'$unwind': '$block.transactions'},
        {'$match': {'block.transactions.metadata.clientID': clientID}}
    ]
    txs = b.getTxByList(list_mongo)
    if txs == None or len(txs) == 0:
        if tx_ids != None and len(tx_ids) > 0:
            ret = True
            err_txids = []
            succ_txids = []
            for txid in tx_ids:
                temp, status = b.get_transaction(txid, include_status=True)
                if temp == None:
                    print(txid+"bu cun zai")
                    return Response({'status': '2'})
                if status == b.BLOCK_INVALID:
                    ret = False
                    print('transaction\'{}\'is invalid'.format(txid))
                    err_txids.append(txid)
                elif status == b.TX_VALID:
                    print('transaction\'{}\'is valid'.format(txid))
                    succ_txids.append(txid)
                else:
                    err_txids.append(txid)
                    return Response({'status': '3'})
            if ret:
                return Response({'status': '1'})
        return Response({'status': '2'})
    return Response({'status': '1'})


@api_view(['POST'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_bill_payhistory(request, key, format=None):
    print('----get_bill_payhistory--start----', time.time())
    bill = Bill()
    data = request.data
    print('get_bill_payhistory--------->', data)

    blockchaininfo = data['blockchaininfo']
    txid = blockchaininfo['txid']
    idx = blockchaininfo['idx']

    tx = bill.b.get_transaction(txid)
    # print('======tx======>',tx)
    # print('======tx.id======>',tx.id)
    # print('======tx.asset======>',tx.asset)
    # print('======tx.asset.id======>',tx.asset.id)
    assetid = tx.id if tx.operation == 'CREATE' else tx.asset['id']
    trans = bill.b.get_transactions_byassetid(assetid)
    # print('======trans======>', trans)
    payhistory = []
    for tran in trans:
        dic = {}
        if tran['inputs'][0]['owners_before'][0] == key:
            dic['payee'] = tran['metadata']['to']['name']
            for output in tran['outputs']:
                if output['public_keys'][0] != key:
                    dic['amount'] = output['amount']
            dic['time'] = tran['metadata']['time']
            dic['clientID'] = tran['metadata']['clientID']
            dic['comment'] = tran['metadata']['comment']
            dic['timestamp'] = tran['metadata']['banktime']
            payhistory.append(dic)
    # print('======payhistory======', payhistory)
    return Response({'pub_key': key, 'payhistory': payhistory})


@api_view(['POST'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_transactions_bypubkeys(request, format=None):
    """
    """
    print('----get_transactions_bypubkeys--start----', time.time())
    b = Bigchain()
    wallet = Wallet()
    data = request.data

    publickeys = data['pubkeys']
    # publickeys = [A_pub_key,B_pub_key]
    starttime = data['start'] + " 00:00:00"
    endtime = data['end'] + " 23:59:59"
    startStamp = int(time.mktime(time.strptime(starttime, "%Y%m%d %H:%M:%S")))
    endStamp = int(time.mktime(time.strptime(endtime, "%Y%m%d %H:%M:%S"))) + 1
    list_mongo = [
        {'$match': {'$and': [{'$or': [{'block.transactions.inputs.owners_before': {'$in': publickeys}},
                                      {'block.transactions.outputs.public_keys': {'$in': publickeys}}]},
                             {'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'$and': [{'block.transactions.metadata.banktime': {'$gt': startStamp}},
                                       {'block.transactions.metadata.banktime': {'$lt': endStamp}}
                                       ]}]}},
        {'$unwind': '$block.transactions'},
        {'$match': {'$and': [{'$or': [{'block.transactions.inputs.owners_before': {'$in': publickeys}},
                                      {'block.transactions.outputs.public_keys': {'$in': publickeys}}]},
                             {'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                             {'$and': [{'block.transactions.metadata.banktime': {'$gt': startStamp}},
                                       {'block.transactions.metadata.banktime': {'$lt': endStamp}}
                                       ]}]}}
    ]
    txs = b.getTxByList(list_mongo)
    print('----b.getTxByList(list_mongo)----', time.time())
    print('----len(txs)-----', len(txs))
    requlist = []
    for block in txs:
        # yu e jie zhuan guo lv
        if candr(candr(block['metadata'], 'from'), 'name') == candr(candr(block['metadata'], 'to'), 'name') and \
                        candr(block['metadata'], 'comment') == "余额结转":
            continue
        if block['metadata']['asset'] == 'money RMB' and \
                        candr(block['metadata'], 'type') != wallet.TRANSAC_TYPE['aggre'] and \
                        candr(block['metadata'], 'type') != wallet.TRANSAC_TYPE['roll']:
            # print('=========timestamp========>', block['metadata']['group'])
            # print('=========operation========>', block['operation'])
            dic = {}
            dic['timestamp'] = block['metadata']['banktime']
            dic['group'] = block['metadata']['group']
            dic['time'] = candr(block['metadata'], 'time')

            dic['RESUME'] = candr(block['metadata'], 'comment')
            dic['clientID'] = candr(block['metadata'], 'clientID')
            dic['blockID'] = block['id']

            iscontinue = False
            for i in range(len(requlist)):
                if dic['blockID'] == requlist[i]['blockID']:
                    iscontinue = True
                    break

            if iscontinue:
                continue

            if 'TRANSFER' == block['operation']:
                dic['subAccNo1'] = block['inputs'][0]['owners_before'][0]
                dic['type'] = 'TRANSFER out'
                for i in range(len(block['outputs'])):
                    if block['outputs'][i]['public_keys'][0] == dic['subAccNo1']:
                        pass
                    else:
                        if block['outputs'][i]['public_keys'][0] == wallet.BLACKHOLE_PUB_KEY or \
                                        block['outputs'][i]['public_keys'][0] == wallet.BLACKHOLE_PUB_KEY_NEW:
                            dic['OPPACCNO'] = candr(candr(block['metadata'], 'to'), 'account')
                        else:
                            dic['OPPACCNO1'] = block['outputs'][i]['public_keys'][0]

                        dic['OPPACCNAME'] = candr(candr(block['metadata'], 'to'), 'name')
                        dic['BankNameTo'] = candr(candr(block['metadata'], 'to'), 'bank')

                        if len(requlist) == 0:
                            dic['TRANAMT'] = block['outputs'][i]['amount']
                            requlist.insert(0, dic)
                        else:
                            if requlist[0]['group'] == block['metadata'][
                                'group']:
                                requlist[0]['TRANAMT'] = requlist[0]['TRANAMT'] + \
                                                         block['outputs'][i][
                                                             'amount']
                            else:
                                dic['TRANAMT'] = block['outputs'][i]['amount']
                                requlist.insert(0, dic)

            elif 'CREATE' == block['operation']:
                # dic['subAccNo1'] = block['inputs'][0]['owners_before'][0]#yinhang
                dic['OPPACCNO1'] = block['outputs'][0]['public_keys'][0]  # ziji
                dic['TRANAMT'] = block['outputs'][0]['amount']
                dic['type'] = 'CREATE'
                if 'from' in block['metadata']:
                    dic['subAccNo'] = candr(candr(block['metadata'], 'from'), 'account')
                    dic['AccNameFrom'] = candr(candr(block['metadata'], 'from'), 'name')
                    dic['BankNameFrom'] = candr(candr(block['metadata'], 'from'), 'bank')
                requlist.insert(0, dic)
    return Response({'statement': requlist})


@api_view(['GET'])
@permission_classes((Or(IsAdmin, IsManager),))
def get_alltransactions(request, format=None):
    """
    """
    print('----get_transactions_bypubkeys--start----', time.time())
    b = Bigchain()
    wallet = Wallet()
    data = request.data
    list_mongo = [
        {'$match': {'$or': [{'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                            {'block.transactions.metadata.asset': wallet.ASSET_TYPE['bill']}]}
         },
        {'$unwind': '$block.transactions'},
        {'$match': {'$or': [{'block.transactions.metadata.asset': wallet.ASSET_TYPE['money']},
                            {'block.transactions.metadata.asset': wallet.ASSET_TYPE['bill']}]}
         },
        {"$sort": {'block.transactions.metadata.group': 1}}
    ]
    txs = b.getTxByList(list_mongo)
    print('----b.getTxByList(list_mongo)----', time.time())
    print('----len(txs)-----', len(txs))
    requlist = []
    for block in txs:
        if candr(block['metadata'], 'type') != wallet.TRANSAC_TYPE['aggre'] and \
                        candr(block['metadata'], 'type') != wallet.TRANSAC_TYPE['roll']:
            # print('=========timestamp========>', block['metadata']['group'])
            # print('=========operation========>', block['operation'])
            dic = {}
            dic['timestamp'] = block['metadata']['banktime']
            dic['group'] = block['metadata']['group']
            dic['metadata'] = block['metadata']
            dic['time'] = candr(block['metadata'], 'time')

            dic['RESUME'] = candr(block['metadata'], 'comment')
            dic['clientID'] = candr(block['metadata'], 'clientID')
            dic['blockID'] = block['id']

            iscontinue = False
            for i in range(len(requlist)):
                if dic['blockID'] == requlist[i]['blockID']:
                    iscontinue = True
                    break

            if iscontinue:
                continue

            if 'TRANSFER' == block['operation']:
                dic['inputkey'] = block['inputs'][0]['owners_before'][0]
                dic['type'] = 'TRANSFER out'
                for i in range(len(block['outputs'])):
                    if block['outputs'][i]['public_keys'][0] == dic['inputkey']:
                        pass
                    else:
                        if block['outputs'][i]['public_keys'][0] == wallet.BLACKHOLE_PUB_KEY or \
                                        block['outputs'][i]['public_keys'][0] == wallet.BLACKHOLE_PUB_KEY_NEW:
                            dic['OPPACCNO'] = candr(candr(block['metadata'], 'to'), 'account')
                        else:
                            dic['outputkey'] = block['outputs'][i]['public_keys'][0]

                        # dic['OPPACCNAME'] = candr(candr(block['metadata'], 'to'), 'name')
                        # dic['BankNameTo'] = candr(candr(block['metadata'], 'to'), 'bank')

                        if len(requlist) == 0:
                            dic['TRANAMT'] = block['outputs'][i]['amount']
                            requlist.insert(0, dic)
                        else:
                            if requlist[0]['group'] == block['metadata'][
                                'group']:
                                requlist[0]['TRANAMT'] = requlist[0]['TRANAMT'] + \
                                                         block['outputs'][i][
                                                             'amount']
                            else:
                                dic['TRANAMT'] = block['outputs'][i]['amount']
                                requlist.insert(0, dic)

            elif 'CREATE' == block['operation']:
                # dic['subAccNo1'] = block['inputs'][0]['owners_before'][0]#yinhang
                dic['outputkey'] = block['outputs'][0]['public_keys'][0]  # ziji
                dic['TRANAMT'] = block['outputs'][0]['amount']
                dic['type'] = 'CREATE'

                requlist.insert(0, dic)
    return Response({'statement': requlist})


class JSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ObjectId):
            return str(o)
        return json.JSONEncoder.default(self, o)
